Визуализация степени подгрузки js-файлов
Современные приложения всё больше начинают напоминать полноценное desktop решение, где в итоге запускается build-процесс с помощью grunt и мы получаем один кешируемый js файл. Теперь встаёт вопрос, как бы его загрузить так что-бы показать % подгрузки?
Есть два отдельных скрипта — $script, который инжектит новые script-элементы с обратной связью и progress.js, который симпатично показывает степен ь загрузки. Проблема в том что оба они уже сами по себе тяжёлые, в итоговый загружаемый билд-файл их нельзя вставить, а внедрять в index.html слишком бы его раздуло.
К тому же $script не поддерживает степень загрузки, а progress.js не использует % от ширины страницы. Поэтому я написал более простенький вариант.
$script = function (path, callback, sizeInChars) {
var head = document.getElementsByTagName('head')[0];
var body = document.getElementsByTagName('body')[0];
var div = document.createElement('div');
div.setAttribute('style', 'background-color:#3498db; width:0px;height:3px;transition: width 0.5s linear;');
body.insertBefore(div, body.firstChild);
var src = path + (path.indexOf('?') === -1 ? '?' : '&');
var oReq = new XMLHttpRequest();
oReq.addEventListener("progress", function (e) {
div.style.width = (100 * ( e.lengthComputable ? (e.loaded / e.total) : (e.loaded / sizeInChars))) + '%';
}, false);
oReq.onreadystatechange = function (e) {
if (oReq.readyState != 4) return;
var el = document.createElement('script');
el.text = oReq.responseText;
head.insertBefore(el, head.lastChild);
callback();
window.setTimeout(function () {
div.remove();
}, 500);
};
oReq.open('GET', src, true);
oReq.send(null);
}
Итого — js файлы подгружаются как текст через ajax, внедряются (без eval), вызывается callback, при этом показывается div отражающий степень загрузки. Единственная проблема — вы должны знать размер загружаемого файла, что в случае nginx + gzip не приходит с заголовками. Поэтому приходится использовать например так..
$script('/js/app.js', function () {
angular.bootstrap(document, ['myApp']);
}, 4879435);